package com.ifnk.portaljava.dapWeb.dapweb;
/**
 * <p>Title: 转换pcap格式tshark解码类</p>
 *
 * <p>Description: </p>
 *
 * <p>Copyright: Copyright (c) 2010</p>
 *
 * <p>Company: </p>
 *
 * @author WenSheng.Song.hlyt@gmail.com
 * @version 1.0
 */

import com.ifnk.portaljava.dapWeb.dataPacket.TransformFunction;
import com.ifnk.portaljava.dapWeb.pacp.Pacp_file_header;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.*;
import org.dom4j.io.SAXReader;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/*
 * 转换成PCAP格式（需要参考包头里的协议类型），
 * 调用TSHARK（根据包协议的不同需要给出不同的参数）做解码生成两种XML文件，
 * 对XML文件做格式化以满足界面的需求
 */
public class SignallingPacket {
    private static Log loger = LogFactory.getLog(SignallingPacket.class);
    private PacketHeader header = new PacketHeader();


    public byte[] convertPacketToPcap(byte[] pkt) {
        byte[] data = TransformToDataPacket(pkt);
        int complementCode = (((header.getType() & 0xf3) << 8 | header
                .getSubType()) == 0x04) ? 2 : 0;
        @SuppressWarnings("unused")
        int pcaplen = header.getLen() - 20 - complementCode;// pkt内容的2个字符的补位
        // pcap文件头
        Pacp_file_header pcapfile = new Pacp_file_header();
//		int len = pcaplen;
        if (header.getSubType() == 0x00 || header.getType() == (byte) 0x8c || header.getSubType() == (byte) 0x8c) { //why subtype == 0x00 => 0x8c ???
            pcapfile.setLinktype(0x8c000000);
        } else if (header.getSubType() == 0x01) {
//			len = pcaplen + 16;
            pcapfile.setLinktype(0xb1000000);
        } else if (header.getSubType() == 0x04) {
            pcapfile.setLinktype(0x01000000);
        } else if (header.getSubType() == 0x05) {
            pcapfile.setLinktype(0x6b000000);
        } else if (header.getSubType() == 0x09) { // sdtp soft capture
            pcapfile.setLinktype(0x93000000);
        }
        // pcap文件头和数据头
//		byte[] data = new byte[40];
        // 文件头24字节
        byte[] fileheader = pcapfile.fileHeader();

        byte[] packet = new byte[fileheader.length + data.length];
        System.arraycopy(fileheader, 0, packet, 0, fileheader.length);
        System.arraycopy(data, 0, packet, fileheader.length, data.length);
        return packet;
    }

    public static byte[] intToByteArray(int value) {
        byte[] b = new byte[4];
        for (int i = 0; i < 4; i++) {
            int offset = (b.length - 1 - i) * 8;
            b[i] = (byte) ((value >>> offset) & 0xFF);
        }
        return b;
    }

    private byte[] reverseByteArrays(byte[] array, boolean flag) {
        if (flag) {
            int count = array.length - 1;
            byte[] arrays = new byte[array.length];
            for (int i = 0; i < arrays.length; i++) {
                arrays[i] = array[count];
                count--;
            }
            return arrays;
        } else {
            return array;
        }
    }

    private byte[] getPcapHeaderByteData(byte[] ts, int caplen, int len, boolean flag) {
		/*
		 * *ts：    8字节 抓包时间 4字节表示秒数，4字节表示微秒数
 			caplen：4字节 保存下来的包长度（最多是snaplen，比如68字节）
 			len：   4字节 数据包的真实长度，如果文件中保存的不是完整数据包，可能比caplen大
		 */
        byte[] header = new byte[16];
        byte[] caplenByte = this.reverseByteArrays(TransformFunction
                .intToByteArray(caplen), flag);
        byte[] lenByte = this.reverseByteArrays(TransformFunction
                .intToByteArray(len), flag);
        System.arraycopy(ts, 0, header, 0, 8);
        System.arraycopy(caplenByte, 0, header, 8, 4);
        System.arraycopy(lenByte, 0, header, 12, 4);
        return header;
    }

    // 概要信息解码 参数是tshark命令
    public String generalInfoDecoding(String tshark, int messageNo) {
        try {
            Process process = Runtime.getRuntime().exec(tshark);
//		StringBuffer  out  =  new  StringBuffer();  
            InputStream in = process.getInputStream();

            long count = System.currentTimeMillis() / 1000;
            while (true) {
                if (System.currentTimeMillis() / 1000 - count > 30) {
                    throw new Exception("InputStream no data");
                }
                if (in.available() <= 0) {
                    Thread.sleep(200);
                    continue;
                } else if (in.available() > 0) {
				/*
				byte[] b = new byte[5000];
				  for  (int  n;  (n  =  in.read(b))  !=  -1;)  {   
					out.append(new  String(b,  0,  n));   
					System.out.println("Tshark in ");
					System.out.println(out.toString());
				 }  
			*/
                    String message = readXMLFile(in, messageNo);
                    loger.info("generalInfoDecoding " + message);
                    return message;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "null";
    }

    @SuppressWarnings("unchecked")
    public static String readXMLFile(InputStream in, int messageNo)
            throws DocumentException, IOException {
        SAXReader sax = new SAXReader();

        sax.setEncoding("GBK");
        Document document = sax.read(in);
        Element root = document.getRootElement();
        // 取得structure节点
        Element structure = root.element("structure");
        // 取得structure节点的所有子节点
        List nodes = structure.elements();
        Iterator its = nodes.iterator();
        List header = new ArrayList();
        while (its.hasNext()) {
            Element section = (Element) its.next();
            String value = section.getText();
            value = value.replace(" ", "_");
            header.add(value);
        }

        // 取得所有的packet节点的集合
        List packets = root.elements("packet");
        Iterator ps = packets.iterator();
        List values = new ArrayList();
        while (ps.hasNext()) {
            // 每一个packet节点
            Element packet = (Element) ps.next();
            // 给packet添加SequenceNo属性
            // 取得packet节点下的所有的section节点的集合
            List sections = packet.elements();
            Iterator it = sections.iterator();
            List value = new ArrayList();
            while (it.hasNext()) {
                // 每一个section节点
                Element element = (Element) it.next();
                // 取得section节点的值
                String text = element.getText();
                value.add(text);
            }
            values.add(value);
        }
        return XMLDocumenttoString(header, values, messageNo);
    }

    @SuppressWarnings("unchecked")
    public static String XMLDocumenttoString(List header, List values,
                                             int messageNo) {
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement("root");
        Iterator it = values.iterator();
        while (it.hasNext()) {
            Element packet = root.addElement("packet");
            List list = (List) it.next();
            Iterator valueIt = list.iterator();
            Iterator headIt = header.iterator();
            while (valueIt.hasNext() && headIt.hasNext()) {
                String field = (String) headIt.next();
                if ("No.".equals(field)) {
                    packet.addElement("No").setText(messageNo + "");
                    valueIt.next();
                } else {
                    packet.addElement((String) field).setText(
                            (String) valueIt.next());
                }
            }
        }
        root = document.getRootElement();
        Element packet = root.element("packet");
        packet.addAttribute("messageNo", messageNo + "");
        // loger.info("pkt xml " + document.asXML());
        return document.asXML();
    }

    // 详细信息解码
    public CDRBean informationDecoding(String tshark, String filepath,
                                       CDRBean cdrBean, byte[] data, boolean decode, boolean decodeToXML) throws Exception {
        String treeXml = "";
        if (decodeToXML) {
            treeXml = decodePCAPToXML(tshark);
        }
        if (decode) {
            // 获取二进制源数据
            ReadBinaryUtil binaryUtil = new ReadBinaryUtil();
            cdrBean = binaryUtil.readBinaryToString(data, cdrBean);
        }
        cdrBean.setTree(treeXml);
        return cdrBean;
    }

    public String decodePCAPToXML(String tshark) throws Exception {
        Process process = Runtime.getRuntime().exec(tshark);
        InputStream in = process.getInputStream();
        long count = System.currentTimeMillis() / 1000;
        while (true) {
            if (System.currentTimeMillis() / 1000 - count > 30) {
                throw new Exception("InputStream no data");
            }
            if (in.available() <= 0) {
                Thread.sleep(200);
                continue;
            } else if (in.available() > 0) {
                String treeXml = parse(in);
                return treeXml;
            }
        }
    }

    @SuppressWarnings("unchecked")
    public static String parse(InputStream inn) throws IOException,
            DocumentException {
        SAXReader sax = new SAXReader();
        InputStreamReader strInStream = new InputStreamReader(inn, "GBK");
        Document document = sax.read(strInStream);
        // 将proto节点的名字改为field
        List pro = document.selectNodes("//proto");
        Iterator itr = pro.iterator();
        while (itr.hasNext()) {
            Element element = (Element) itr.next();
            element.setName("field");
        }
        String xml = null;
        List list = document.selectNodes("//field");
        Iterator it = list.iterator();
        int i = 1;
        while (it.hasNext()) {
            Element fieldElement = (Element) it.next();
            Attribute attr = fieldElement.attribute("showname");
            // 如果没有showname属性，则获取show属性值并把show属性改为shownane
            if (attr == null) {
                attr = fieldElement.attribute("show");
                if (attr != null) {
                    fieldElement.addAttribute("showname", attr.getValue());
                    fieldElement.remove(attr);
                }
            }
            fieldElement.addAttribute("id", "" + i++);
            Attribute hide = fieldElement.attribute("hide");
            if (hide != null && "yes".equals(hide.getValue())) {
                fieldElement.getParent().remove(fieldElement);
            }
        }

        // 删除name=geninfo的节点
        Iterator geninfos = document.getRootElement().selectNodes("//field[@name='geninfo']").iterator();
        Iterator packets = document.selectNodes("//packet").iterator();
        while (packets.hasNext()) {
            if (geninfos.hasNext()) {
                Element node = (Element) geninfos.next();
                ((Element) packets.next()).remove(node);
            }
        }
        // 删除packet节点
        if (document.getRootElement().elements().size() == 1) {
            Element packet = document.getRootElement().element("packet");
            List nodes = packet.elements();
            document.getRootElement().remove(packet);
            document.getRootElement().setContent(nodes);
        }

        List lists = document.selectNodes("//field");
        Iterator its = lists.iterator();
        while (its.hasNext()) {
            Element field = (Element) its.next();
            if (field.attribute("show") == null
                    && field.attribute("showname") == null) {
                List fiel = field.elements();
                if (fiel.size() > 0) {
                    Element first = (Element) fiel.get(0);
                    List second = first.elements();
                    List itor = first.attributes();
                    field.setAttributes(itor);
                    field.remove(first);
                    field.setContent(second);
                }
            }
        }
        xml = document.asXML();
        return xml;
    }

    //将数据转换成 '数据包头 + 数据包'格式的数据包
    public byte[] TransformToDataPacket(byte[] data) {
        // 原始消息数据包头(解码data中的包头)
        header.DecodeHeader(data);
        // cap文件中的时间戳
        byte[] ts = new byte[8];
        byte[] ts_s = intToByteArray(header.getTs_s());
//        System.out.println("ts_s = " + header.getTs_s());
        byte[] ts_ns = intToByteArray(header.getTs_ns() / 1000);
        // 反序
        ts_s = this.reverseByteArrays(ts_s, true);
        ts_ns = this.reverseByteArrays(ts_ns, true);
        System.arraycopy(ts_s, 0, ts, 0, 4);
        System.arraycopy(ts_ns, 0, ts, 4, 4);

        @SuppressWarnings("unused")
        int flen = header.getSc() & 0x3;// len * 4 – sizeof(pkt_hdr) –
        // flen
        int complementCode = (((header.getType() & 0xf3) << 8 | header
                .getSubType()) == 0x04) ? 2 : 0;
        int pcaplen = header.getLen() - 20 - complementCode;// pkt内容的2个字符的补位
        byte[] sslheader = new byte[0];
        int len = pcaplen;
        if (header.getSubType() == 0x01) {
            len += 16;
            sslheader = new byte[16];
            sslheader[0] = 0x04;
            sslheader[15] = 0x30;
            if ((header.getSc() & 0x40) == 0) {
                sslheader[6] = 0x1;
            }
        }
        // 数据包头16字节
        byte[] pcapHeader = getPcapHeaderByteData(ts, len, len, true);

        byte[] packet = new byte[pcapHeader.length + sslheader.length + pcaplen];
        int pos = 0;
        System.arraycopy(pcapHeader, 0, packet, pos, pcapHeader.length);
        pos += pcapHeader.length;
        System.arraycopy(sslheader, 0, packet, pos, sslheader.length);
        pos += sslheader.length;
        System.arraycopy(data, 20 + complementCode, packet, pos, pcaplen);
        return packet;
    }

}
